// Author : Anushi Shah, Kyoungho An

// $Id$
#include "ace/OS_NS_unistd.h"  // for OS API
#include "ace/Get_Opt.h"  // for parsing command line
#include "ace/Log_Msg.h"  // for logging messages
#include "ace/Reactor.h"  // Reactor class

#include "tao/ORB_Core.h" // the ORB itself
#include "tao/RTCORBA/RTCORBA.h"  // all the RTCORBA capabilities

#include "NEANodeInternalClient.h" // our header
#include "tao/RTCORBA/Priority_Mapping_Manager.h"
#include "ace/Sched_Params.h"

// constructor
NEANodeInternalClient::NEANodeInternalClient (CORBA::ORB_ptr orb)
  : 
    orb_ (CORBA::ORB::_duplicate (orb)),
    ior_ (CORBA::string_dup (ACE_TEXT("file://../actuator")))
{
}

/// destructor
NEANodeInternalClient::~NEANodeInternalClient (void)
{
}

// parse the command line arguments other than those that will be consumed by
// the ORB
int NEANodeInternalClient::parse_args (int argc, ACE_TCHAR *argv[])
{
  ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("F:k:"));
  int c;

  while ((c = get_opts ()) != -1)
    switch (c)
      {
      case 'k':  // if IOR of diagnostics module should be obtained via command
                 // line
        this->ior_ = get_opts.opt_arg ();
        break;

      case 'F':  // tire pressure sensing period
        this->freq_ = ACE_OS::atoi (get_opts.opt_arg ());
        break;

      case '?':
      default:
        ACE_ERROR_RETURN ((LM_ERROR,
                           "usage:  %s "
                           "-F <tire sensing frequency> "
                           "-k <ior for diagnostic module> "
                           "\n",
                           argv [0]),
                          -1);
      }

  // Indicates sucessful parsing of the command line
  return 0;
}

/// initialize
int NEANodeInternalClient::init (void)
{
  try 
    {
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("Grabbing obj ref to Actuator from file: %s\n"),
                  this->ior_.in ()));

      // let us grab the object reference to the Actuator module
      CORBA::Object_var object =
        this->orb_->string_to_object (this->ior_.in ());

      // check error
      if (CORBA::is_nil (object.in ())) {
        // failure to convert into obj ref
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Block::Turnaround::NEANode - bad object ref\n")));
        return -1;
      }

      // now narrow the obj ref to the Actuator type
	  this->actuator_ = Block::Turnaround::TurnaroundActuator::_narrow (object.in ());


      // check error
      if (CORBA::is_nil (this->actuator_.in ())) {
        // failure to narrow
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("Block::Turnaround::NEANode - cannot narrow to Diagnostics\n")));
        return -1;
      }

//   =====================================================================
//    Code to make it Client propagated               
//   ====================================================================

          CORBA::Policy_var policy =
            actuator_->_get_policy(RTCORBA::PRIORITY_MODEL_POLICY_TYPE);
        
          RTCORBA::PriorityModelPolicy_var priority_policy = 
             RTCORBA::PriorityModelPolicy::_narrow(policy.in());

          if(CORBA::is_nil(priority_policy.in()))
           {
              ACE_ERROR((LM_ERROR,
                    ACE_TEXT ("Messenger object deos not support Priority Model\n")));
              return 1;
           }

           RTCORBA::PriorityModel priority_model =
           priority_policy->priority_model();

           if(priority_model != RTCORBA::CLIENT_PROPAGATED)
           {
              
              ACE_ERROR((LM_ERROR,
                    ACE_TEXT ("Messenger object deosnot support Client Priority Model\n")));
              return 1;    
           }

           CORBA::Object_var curr_obj =
           orb_->resolve_initial_references("RTCurrent");
           
           RTCORBA::Current_var current =
           RTCORBA::Current::_narrow(curr_obj.in());
          
          //**************************************
	curr_obj = this->orb_->resolve_initial_references ("PriorityMappingManager");
      	RTCORBA::PriorityMappingManager_var mapping_manager =
        RTCORBA::PriorityMappingManager::_narrow (curr_obj.in ());

	RTCORBA::PriorityMapping *pm =
        mapping_manager->mapping ();

        int sched_policy =
        this->orb_->orb_core ()->orb_params ()->ace_sched_policy ();

        int max_priority =
        ACE_Sched_Params::priority_max (sched_policy);
        int min_priority =
        ACE_Sched_Params::priority_min (sched_policy);

        CORBA::Short native_priority =
        (max_priority + min_priority) / 2;

        CORBA::Short desired_priority = 0;

       if (pm->to_CORBA (native_priority, desired_priority) == 0)
        ACE_ERROR_RETURN ((LM_ERROR,
                           "Cannot convert native priority %d to corba priority\n",
                           native_priority),
                          -1);
		

           ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("I am Here ***********\n")));

         
          //*************************************

          //CORBA::Short my_priority = 10;
          //RTCORBA::Priority desired_priority = my_priority;
          
          current->the_priority(desired_priority);
          // current->the_priority(get_implicit_thread_CORBA_priority(this->orb_in()));

          //actuator_ -> energize_actuator(10);
// =============================================================================================

      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("Scheduling timer: %d Hz\n"),
                  this->freq_));

      // now let us register ourselves for the timer corresponding to our
      // period. First create the timeout value.
      ACE_Time_Value tm;
      tm.set (1.0/this->freq_);  // use the overloaded function that
                                 // takes in a double.
/*
      // now register
      this->timer_id_ = 
        
	this->reactor ()->schedule_timer (this,  // needs an event handler
                                          0,     // no argument to be passed
                                          tm,
                                          tm);   // time delay
*/      
      if (this->timer_id_ == -1) {
        // failure to register timer
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("ITS::TireSensor - cannot schedule timer\n")));
        return -1;
      }

#if 0
      object =
        this->orb_->resolve_initial_references ("RTCurrent");

      RTCORBA::Current_var current =
        RTCORBA::Current::_narrow (object.in ());

      // We need to set the client thread CORBA priority
      current->the_priority (get_implicit_thread_CORBA_priority (this->orb_.in ()));
#endif

    }
  catch (const CORBA::Exception& ex)
    {
      ex._tao_print_exception ("Exception caught:");
      return -1;
    }

  return 0;
}
